/*
 * sso
 */
package com.jlb.base.service;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWTCreator;
import com.baidu.fsg.uid.UidGenerator;
import com.jlb.core.SessionTools;
import com.jlb.core.enums.SessionEnum;
import com.jlb.core.exceptions.BaseException;
import com.jlb.core.exceptions.PlatformAccountException;
import com.jlb.core.exceptions.UserException;
import com.jlb.core.tools.JwtToken;
import com.jlb.core.tools.redis.RedisUtils;
import com.jlb.core.tools.security.Md5;
import com.jlb.platform.dao.PlatformAccountDAO;
import com.jlb.platform.entity.PlatformAccount;
import com.jlb.platform.entity.PlatformAccountState;
import com.jlb.setting.dao.SettingDAO;
import com.jlb.setting.entity.Setting;
import com.jlb.setting.service.SessionSV;
import com.jlb.user.dao.UserDAO;
import com.jlb.user.entity.User;
import com.jlb.user.entity.UserState;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 会话业务层
 */
@Service("sessionSV")
@Slf4j
public class SessionSVImpl implements SessionSV {


    @Resource
    private UidGenerator uidGenerator;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private SettingDAO settingDAO;

    @Resource
    private UserDAO userDAO;

    @Resource
    private PlatformAccountDAO platformAccountDAO;


    /**
     * 创建会话
     * 1.验证账户密码合法性
     * 2.生成会话
     * 3.记录日志
     *
     * @param account  账户
     * @param password 密码
     * @return token
     */
    @Override
    public String buildUserSession(String account, String password) {
        //1.验证账户密码合法性
        String sessionkey = null;
        Map<String, Object> param = new HashMap<>();
        param.put("account", account);
        if (!password.equals(PlatformAccount.PlatformAccountEnum.Platform.name())) {
            param.put("password", Md5.md5(password));
            param.put("state", UserState.Active.name());
            sessionkey = SessionTools.Instance.genSessionKey(account);
        } else {
            sessionkey = SessionTools.Instance.genSessionKey(account);
        }
        User user = userDAO.load(param);
        if (user == null) {
            throw new UserException(BaseException.BaseExceptionEnum.Account_Error);
        }

        //2.生成会话
        Setting session_Expire_TimeSetting = settingDAO.loadByK(Setting.Key.Session_Expire_Time.name());//会话过期时间
        int session_Expire_Time = Integer.parseInt(session_Expire_TimeSetting.getV());
        Setting token_Expire_TimeSetting = settingDAO.loadByK(Setting.Key.Token_Expire_Time.name());//token过期时间
        long token_Expire_Time = Long.parseLong(token_Expire_TimeSetting.getV());

        JWTCreator.Builder builder = JwtToken.create();
        builder.withClaim(SessionEnum.SessionKey.name(), sessionkey)
                .withClaim(SessionEnum.Code.name(), user.getCode())
                .withClaim(SessionEnum.Session.name(), SessionEnum.UserSession.name())
                .withClaim(SessionEnum.Account.name(), account)
                .withClaim(SessionEnum.Session_Expire_Time.name(), String.valueOf(session_Expire_Time));

        //生成token 给cookie使用 或者前端缓存使用
        Setting token_SecretSetting = settingDAO.loadByK(Setting.Key.Token_Secret.name());

        String token = JwtToken.createToken(builder, token_SecretSetting.getV(), token_Expire_Time);
        redisUtils.set(sessionkey, JSON.toJSONString(user), session_Expire_Time);

        return token;
    }

    /**
     * 创建会话
     * 1.验证账户密码合法性
     * 2.生成会话
     * 3.记录日志
     *
     * @param account  账户
     * @param password 密码
     * @return
     */
    @Override
    public String buildPlatformSession(String account, String password) {
        //1.验证账户密码合法性
        Map<String, Object> param = new HashMap<>();
        param.put("account", account);
        param.put("password", Md5.md5(password));
        param.put("state", PlatformAccountState.Active.name());
        PlatformAccount platformAccount = platformAccountDAO.load(param);
        if (platformAccount == null) {
            throw new PlatformAccountException(BaseException.BaseExceptionEnum.Account_Error);
        }

        //2.生成会话
        Setting session_Expire_TimeSetting = settingDAO.loadByK(Setting.Key.Session_Expire_Time.name());//会话过期时间
        int session_Expire_Time = Integer.parseInt(session_Expire_TimeSetting.getV());
        Setting token_Expire_TimeSetting = settingDAO.loadByK(Setting.Key.Token_Expire_Time.name());//token过期时间
        long token_Expire_Time = Long.parseLong(token_Expire_TimeSetting.getV());

        String sessionkey = SessionTools.Instance.genSessionKey(account);
        JWTCreator.Builder builder = JwtToken.create();
        builder.withClaim(SessionEnum.SessionKey.name(), sessionkey)
                .withClaim(SessionEnum.Code.name(), platformAccount.getCode())
                .withClaim(SessionEnum.Session.name(), SessionEnum.PlatformSession.name())
                .withClaim(SessionEnum.Account.name(), account)
                .withClaim(SessionEnum.Session_Expire_Time.name(), String.valueOf(session_Expire_Time));

        //生成token 给cookie使用 或者前端缓存使用
        Setting token_SecretSetting = settingDAO.loadByK(Setting.Key.Token_Secret.name());

        String token = JwtToken.createToken(builder, token_SecretSetting.getV(), token_Expire_Time);
        redisUtils.set(sessionkey, JSON.toJSONString(platformAccount), session_Expire_Time);

        return token;
    }

    /**
     * 刷新token
     *
     * @param token token
     * @return token
     */
    @Override
    public String refresh(String token) {
        //session会话过期时间
        String sso_secret = settingDAO.loadByK(Setting.Key.Token_Secret.name()).getV();

        String account = JwtToken.getTokenValue(token, sso_secret, SessionEnum.Account.name());
        String sessionKey = SessionTools.Instance.genSessionKey(account);

        if (!redisUtils.hasKey(sessionKey)) {
            throw new BaseException(BaseException.BaseExceptionEnum.Session_Error);
        }

        String session_expire_timeStr = JwtToken.getTokenValue(token, sso_secret, SessionEnum.Session_Expire_Time.name());
        if (session_expire_timeStr == null) {
            throw new BaseException(BaseException.BaseExceptionEnum.Session_Error);
        }
        int session_expire_time = Integer.parseInt(session_expire_timeStr);

        JWTCreator.Builder builder = JwtToken.create();
        builder.withClaim(SessionEnum.SessionKey.name(), sessionKey)
                .withClaim(SessionEnum.Code.name(), JwtToken.getTokenValue(token, sso_secret, SessionEnum.Code.name()))
                .withClaim(SessionEnum.Session.name(), JwtToken.getTokenValue(token, sso_secret, SessionEnum.Session.name()))
                .withClaim(SessionEnum.Account.name(), account)
                .withClaim(SessionEnum.Session_Expire_Time.name(), String.valueOf(session_expire_time));
        token = JwtToken.createToken(builder, sso_secret, session_expire_time);

        redisUtils.expire(sessionKey, session_expire_time);//刷新局部会话过期时间
        return token;
    }


}
